package com.red.star.wechat.work.core.interceptor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.red.star.wechat.data.entity.Mall;
import com.red.star.wechat.data.entity.vo.UserFromApi;
import com.red.star.wechat.data.mappers.MallMapper;
import com.red.star.wechat.data.utils.CheckUtil;
import com.red.star.wechat.data.utils.DateNewUtil;
import com.red.star.wechat.data.utils.GuavaCache;
import com.red.star.wechat.work.constant.Constant;
import com.red.star.wechat.work.constant.RoleConstant;
import com.red.star.wechat.work.core.security.MyAccessDecisionManager;
import com.red.star.wechat.work.entity.Admin;
import com.red.star.wechat.work.entity.Role;
import com.red.star.wechat.work.site.admin.mapper.AdminMapper;
import com.red.star.wechat.work.utils.ApiUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.keygen.KeyGenerators;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;

@Service
public class MyFilterSecurityInterceptor extends FilterSecurityInterceptor
        implements Filter {

    @Resource
    @Qualifier(value = "securityMetadataSource")
    private FilterInvocationSecurityMetadataSource securityMetadataSource;

    @Resource
    private MallMapper mallMapper;

    @Resource
    private AdminMapper adminMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        FilterInvocation fi = new FilterInvocation(request, response, chain);
        try {
            boolean isSsoLogin = ssoLogin(request);
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        invoke(fi);
    }

    @Override
    public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
        return this.securityMetadataSource;
    }

    @Override
    public Class<? extends Object> getSecureObjectClass() {
        return FilterInvocation.class;
    }

    @Override
    public void invoke(FilterInvocation fi) throws IOException,
            ServletException {
        InterceptorStatusToken token = super.beforeInvocation(fi);//MyInvocationSecurityMetadataSource.getAttributes()方法
        try {
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
        } finally {
            super.afterInvocation(token, null);//MyAccessDecisionManager.decide()方法进行对比
        }
    }

    @Override
    public SecurityMetadataSource obtainSecurityMetadataSource() {
        return this.securityMetadataSource;
    }

    @Resource
    public void setAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager) {
        super.setAccessDecisionManager(myAccessDecisionManager);
    }

    @Override
    public void setSecurityMetadataSource(
            FilterInvocationSecurityMetadataSource newSource) {
        this.securityMetadataSource = newSource;
    }

    @Override
    public void destroy() {
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
    }

    /**
     * 单点登录入口
     * <p>
     * channel 为空则是微信后台登录，为market为全民营销登录
     *
     * @param req
     * @return
     * @throws IOException
     * @throws ExecutionException
     */
    private boolean ssoLogin(ServletRequest req) throws IOException, ExecutionException {
        HttpServletRequest request = (HttpServletRequest) req;
        String url = request.getRequestURI();
        String ssoSessionId = request.getParameter("ssoSessionId");
        String channel = request.getParameter("channel");
        if ((url.contains("/work/home") || url.contains("/work/mallWelcome") || url.contains("/work/imageActivity.html")) && !CheckUtil.isEmpty(ssoSessionId)) {
            String user = GuavaCache.get(ssoSessionId).toString();
            if (!CheckUtil.isEmpty(user) && "fail".equals(user)) {
                user = configUser(ssoSessionId, channel);
                if (CheckUtil.isEmpty(user)) {
                    return false;
                }
                GuavaCache.put(ssoSessionId, user);
            }
            UserFromApi userFromApi;
            JSONObject object = JSONObject.parseObject(user);
            if (!CheckUtil.isEmpty(object) && (Integer.valueOf(200).equals(object.get("code")) || Integer.valueOf(0).equals(object.get("errcode")))) {
                String body = CheckUtil.isEmpty(object.getString("dataMap")) ? object.getString("data") : object.getString("dataMap");
                userFromApi = JSON.parseObject(body, UserFromApi.class);
                if (!CheckUtil.isEmpty(userFromApi)) {
                    //判断是否为商场用户
                    if (userFromApi.getUnitType().equals("5")) {
                        Mall mall = mallMapper.findMallByOmsCode(userFromApi.getUnitCode());
                        if (CheckUtil.isEmpty(mall)) {
                            return false;
                        }
                        //TODO:此处有遗留问题，如果全民营销的商场后续开通了商场，此处赋值的角色会缺少
                        Admin admin = adminMapper.findAdminByMallCode(mall.getMallCode(), userFromApi.getUserAccount());
                        if (!CheckUtil.isEmpty(admin)) {
                            Set<Role> set = adminMapper.findRoleSetByAdminId(admin.getId());
                            if (!CheckUtil.isEmpty(set)) {
                                admin.setRoles(set);
                                admin.setAuthorities(set);
                                initUserDetail(admin, request);
                                return true;
                            } else {
                                return false;
                            }
                        } else {
                            admin = new Admin();
                            admin.setMallCode(mall.getMallCode());
                            admin.setName(userFromApi.getUserName());
                            admin.setEnumValue("mall_code");
                            admin.setUsername(userFromApi.getUserAccount());
                            admin.setBRegionCode(mall.getBRegionCode());
                            admin.setSRegionCode(mall.getSRegionCode());
                            String s = KeyGenerators.string().generateKey();
                            admin.setPassword(passwordEncoder.encode(s));
                            admin.setCreateTime(DateNewUtil.getCurrentDateTime());
                            admin.setUpdateTime(admin.getCreateTime());
                            adminMapper.insert(admin);
                            Set<Role> set = null;
                            if (Constant.CHANNEL_MARKET.equals(channel) && mall.getRealStatus() == 0) {//全民营销过来且商场未启用
                                set = findRoleByEnum(RoleConstant.MACALLINE_WORK_IMAGE);
                            } else {
                                set = findRoleByEnum(RoleConstant.MACALLINE_WORK_MALL);
                            }
                            for (Role role1 : set) {
                                adminMapper.insertAdminRole(admin.getId(), role1.getId());
                            }
                            admin.setRoles(set);
                            admin.setAuthorities(set);
                            initUserDetail(admin, request);
                            return true;
                        }
                    } else {
                        Admin oldAdmin = null;
                        if (Constant.CHANNEL_MARKET.equals(channel)) {
                            //全名营销
                            oldAdmin = adminMapper.findAdminByUsernameAValue(userFromApi.getUserAccount() + "-" + userFromApi.getUnitType(), Constant.ENUM_VALUE_REDSTART_MANAG);
                        } else {
                            //微信后台
                            oldAdmin = adminMapper.findAdminByUsernameAValue(userFromApi.getUserAccount(), Constant.ENUM_VALUE_REDSTART_MANAG);
                        }
                        if (!CheckUtil.isEmpty(oldAdmin)) {
                            Set<Role> set = adminMapper.findRoleSetByAdminId(oldAdmin.getId());
                            if (!CheckUtil.isEmpty(set)) {
                                oldAdmin.setRoles(set);
                                oldAdmin.setAuthorities(set);
                                initUserDetail(oldAdmin, request);
                                return true;
                            } else {
                                return false;
                            }
                        } else {
                            oldAdmin = new Admin();
                            oldAdmin.setName(userFromApi.getUserName());
                            oldAdmin.setEnumValue("redstart_manag");
                            if (Constant.CHANNEL_MARKET.equals(channel)) {
                                //全名营销
                                oldAdmin.setUsername(userFromApi.getUserAccount() + "-" + userFromApi.getUnitType());
                            } else {
                                //微信后台
                                oldAdmin.setUsername(userFromApi.getUserAccount());
                            }
                            String s = KeyGenerators.string().generateKey();
                            oldAdmin.setPassword(passwordEncoder.encode(s));
                            oldAdmin.setCreateTime(DateNewUtil.getCurrentDateTime());
                            oldAdmin.setUpdateTime(oldAdmin.getCreateTime());
                            adminMapper.insert(oldAdmin);
                            Set<Role> set = findRoleByEnum(RoleConstant.MACALLINE_WORK_ADMIN);
                            for (Role role1 : set) {
                                adminMapper.insertAdminRole(oldAdmin.getId(), role1.getId());
                            }
                            oldAdmin.setRoles(set);
                            oldAdmin.setAuthorities(set);
                            initUserDetail(oldAdmin, request);
                            return true;
                        }
                    }
                }
            }
            return true;
        } else {
            return false;
        }

    }

    /**
     * session管理
     *
     * @param admin
     * @param request
     */
    private void initUserDetail(Admin admin, HttpServletRequest request) {
        request.getSession().setAttribute("name", admin.getName());
        Authentication authentication = new UsernamePasswordAuthenticationToken(admin, "", admin.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
        request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
    }

    /**
     * 单点登录用户信息获取
     *
     * @param ssoSessionId
     * @param channel
     * @return
     * @throws IOException
     */
    private String configUser(String ssoSessionId, String channel) throws IOException {
        String user = "";
        if (CheckUtil.isEmpty(channel)) {
            //微信后台登录
            user = ApiUtil.loginUserFromApi(ssoSessionId);
        } else if (Constant.CHANNEL_MARKET.equals(channel)) {
            //全民营销登录
            user = ApiUtil.loginUserFromQMYX(ssoSessionId);
        } else {
            //不支持的单点登录
            return user;
        }
        return user;
    }

    private Set<Role> findRoleByEnum(String... enumValueSet) {
        List<String> enumValueList = Arrays.asList(enumValueSet);
        Set<Role> roleSet = adminMapper.findRoleSetByEnumValue(enumValueList);
        return roleSet;
    }


}
